/**
 ********************************************************************
 * @author roocket
 * @file    pwm.c
 * @version V0.0.0
 * @date    2024/4/26
 * @brief   This file is to indicate pwm functions. 
 * @attention Code file rules:
 * rule: file encoding use UTF8;
 * rule: max line length 120 characters;
 * rule: line separator \r\n;
 * rule: use clion auto code format tool.
 */
#include "pwm.h"

int pwm_controller_init(struct pwm_controller *pwm)
{
    int handler;
	int exp_fd;
    int period_fd;
    int duty_fd;
    char pwmx[128] = "";
    int res;
    char node_buffer[128] = "";
    char period_buffer[128] = "";
    char duty_buffer[128]  = "";
    int len;

    /* set export */
    snprintf(pwmx, sizeof(pwmx), "%s%d/export", PWM_CONTROLLER_SYSFS_PWM_CHIPX, pwm->which_chip);
    
    exp_fd = open(pwmx, O_WRONLY);
    if (-1 == exp_fd) {
        perror("open pwm export error");
        goto exp;
    }

    len = snprintf(node_buffer, sizeof(node_buffer), "%d", pwm->node);
    res = write(exp_fd, node_buffer, len);
    if (-1 == res) {
        perror("write node error");
        goto exp;
    }
    close(exp_fd);
    
    /* set period */
    memset(pwmx, 0x00, 128);
    snprintf(pwmx, sizeof(pwmx), "%s%d/pwm%d/period", PWM_CONTROLLER_SYSFS_PWM_CHIPX, pwm->which_chip, pwm->node);
    
    period_fd = open(pwmx, O_WRONLY);
    if (-1 == period_fd) {
        perror("open pwm period error");
        return -1;
    }

    len = snprintf(period_buffer, sizeof(period_buffer), "%d", pwm->period);
    res = write(period_fd, period_buffer, len);
	if (-1 == res) {
        perror("write period error");
        goto period;
    }

    /* set duty cycle */
    memset(pwmx, 0x00, 128);
    snprintf(pwmx, sizeof(pwmx), "%s%d/pwm%d/duty_cycle", PWM_CONTROLLER_SYSFS_PWM_CHIPX, pwm->which_chip, pwm->node);
    
    duty_fd = open(pwmx, O_WRONLY);
    if (-1 == duty_fd) {
        perror("open pwm period error");
        return -1;
    }

    len = snprintf(duty_buffer, sizeof(duty_buffer), "%d", pwm->duty_cycle);
    res = write(duty_fd, duty_buffer, len);
	if (-1 == res) {
        perror("write duty cycle error");
        goto duty;
    }

    /* get handler of enable for pwm */
    memset(pwmx, 0x00, 128);
    snprintf(pwmx, sizeof(pwmx), "%s%d/pwm%d/enable", PWM_CONTROLLER_SYSFS_PWM_CHIPX, pwm->which_chip, pwm->node);

    handler = open(pwmx, O_WRONLY);
    if (-1 == handler) {
        perror("open pwm handler error");
        return -1;
    }
    return handler;

exp:
    close(exp_fd);
    return -1;
period:
    close(period_fd);
    return -1;
duty:
    close(duty_fd);
    return -1;
}

int pwm_controller_deinit(struct pwm_controller *pwm)
{
    int res;
    char pwm_unexport[128] = "";
    int unexport;
    char buffer[128] = "";
    int len;

    snprintf(pwm_unexport, sizeof(pwm_unexport), "%s%d/unexport", PWM_CONTROLLER_SYSFS_PWM_CHIPX, pwm->which_chip);
    
    unexport = open(pwm_unexport, O_WRONLY);
    if (-1 == unexport) {
        perror("open pwm unexport error");
  	    return -1;
    }
   
    len = snprintf(buffer, sizeof(buffer), "%d", pwm->node);
    res = write(unexport, buffer, len);
    if (-1 == res) {
        perror("write unexport node error");
        goto out;
    }
    
    close(unexport);
	return 0;

out:
    close(unexport);
    return -1;
}

/* start pwm */
int pwm_controller_start(int handler)
{
    int res;
    unsigned char enable = 1;
    char buffer[32] = "";
    int len;

    len = snprintf(buffer, sizeof(buffer), "%d", enable);

    res = write(handler, buffer, len);
    if (-1 == res) {
        perror("write enable error");
        return -1;
    }
    return 0;
}

/* stop pwm */
int pwm_controller_stop(int handler)
{
    int res;
    unsigned char disable = 0;
    char buffer[32] = "";
    int len;

    len = snprintf(buffer, sizeof(buffer), "%d", disable);    

    res = write(handler, buffer, len);
    if (-1 == res) {
        perror("write disable error");
        return -1;
    }
    return 0;
}
